﻿using System;
using System.Drawing;
using System.IO;
using System.Text.RegularExpressions;
using SharpZipLib.Zip;
using Tsanie.ShellExt.Definitions;

namespace Tsanie.ShellExt.Thumbnail
{
    public class EpubProvider : ThumbnailBaseProvider
    {
        public override string ProviderName { get { return "Thumbnail.Epub"; } }
        public override ProviderType Type { get { return ProviderType.Thumbnail; } }
        public override string[] Exts { get { return new[] { ".epub" }; } }
        public override string Creator { get { return "Tsanie"; } }

        public override Bitmap GetBitmap(string filename, ThumbnailFlags flags, int colorDepth, Size size)
        {
            return GetBackgroundFromEpub(filename);
        }

        public Bitmap GetBackgroundFromEpub(string filename)
        {
            string bgFile = null;
            Bitmap bmp = null;
            ZipEntry entry;
            using (FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                if (stream.Length == 0)
                {
                    Common.OutputDebugString("get_GetImage(void):: Error - file length == 0. {0}", filename);
                    stream.Close();
                    return null;
                }
                try
                {
                    using (ZipInputStream zip = new ZipInputStream(stream))
                    {
                        while (bgFile == null && ((entry = zip.GetNextEntry()) != null))
                        {
                            if (entry.Name.ToLower() == "itunesmetadata.plist")
                            {
                                // 找到.plist文件
                                if (entry.Size <= 0)
                                {
                                    Common.OutputDebugString("GetBackgroundFromEpub(Stream):: Warning entry size == 0. {0}", entry.Name);
                                    continue;
                                }
                                byte[] bs = new byte[entry.Size];
                                using (StreamReader reader = new StreamReader(new MemoryStream(bs)))
                                {
                                    zip.Read(bs, 0, bs.Length);
                                    string line;
                                    while ((line = reader.ReadLine()) != null)
                                    {
                                        if (line.Trim('\t', ' ') == "<key>cover-image-path</key>")
                                        {
                                            line = reader.ReadLine().Trim('\t', ' ');
                                            // example: <string>OPS/images/cover.jpg</string>
                                            line = line.Substring(8, line.LastIndexOf("</string>") - 8);
                                            // 找到
                                            bgFile = line.ToLower();
                                            break;
                                        }
                                    }
                                    reader.Close();
                                }
                                bs = null;
                            }
                            else if (entry.Name.Substring(entry.Name.LastIndexOf('.') + 1).ToLower() == "opf")
                            {
                                byte[] bs = new byte[entry.Size];
                                using (StreamReader reader = new StreamReader(new MemoryStream(bs)))
                                {
                                    zip.Read(bs, 0, bs.Length);
                                    string line;
                                    string id = null;
                                    while ((line = reader.ReadLine()) != null)
                                    {
                                        if (id == null)
                                        {
                                            // example: <meta name="cover" content="cover-image"/>
                                            Match m = Regex.Match(line, "<meta[ ]+name=\"cover\"[ ]+content=\"([^\"]+)\"", RegexOptions.IgnoreCase);
                                            if (m.Success)
                                            {
                                                id = m.Groups[1].Value;
                                                // .jpg
                                                if (id.Length > 4 && id.Substring(id.LastIndexOf('.')).ToLower() == ".jpg")
                                                {
                                                    bgFile = id.ToLower();
                                                    break;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            // example: <item id="cover-image" href="images/cover.jpg" media-type="image/jpeg"/>
                                            Match m = Regex.Match(line, "<item[ ]+id=\"" + id + "\"[ ]+href=\"([^\"]+)\"", RegexOptions.IgnoreCase);
                                            if (m.Success)
                                            {
                                                // entry.Name.Substring(0, entry.Name.LastIndexOf('/')) + "/" + m.Groups[1].Value
                                                bgFile = m.Groups[1].Value.ToLower();
                                                break;
                                            }
                                        }
                                    }
                                    reader.Close();
                                }
                                bs = null;
                            }
                        }
                        zip.Close();
                    }
                }
                catch (Exception e)
                {
                    Common.OutputError(string.Format("GetBackgroundFromEpub('{0}')", filename), e);
                    stream.Close();
                    return null;
                }

                if (bgFile == null)
                {
#if DEBUG
                    Common.OutputDebugString("GetBackgroundFromEpub(Stream):: Warning '{0}' hasn't a cover.", filename);
#endif
                    return null;
                }
            }
            using (FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                using (ZipInputStream zip = new ZipInputStream(stream))
                {
                    while ((entry = zip.GetNextEntry()) != null)
                    {
                        if (bgFile != null && (entry.Name.ToLower() == bgFile || entry.Name.ToLower().EndsWith(bgFile)))
                        {
                            // 找到背景图片
                            if (entry.Size <= 0)
                            {
                                Common.OutputDebugString("GetBackgroundFromEpub(Stream).GetImage:: Warning entry size == 0. {0}", entry.Name);
                                continue;
                            }
                            byte[] bs = new byte[entry.Size];
                            zip.Read(bs, 0, bs.Length);
                            try
                            {
                                bmp = Bitmap.FromStream(new MemoryStream(bs)) as Bitmap;
                                break;
                            }
                            catch (Exception e)
                            {
                                Common.OutputDebugString("GetBackgroundFromEpub(Stream).GetImage:: Exception, {0} - {1}", e.GetType().FullName, e.Message);
                            }
                            bs = null;
                        }
                    }
                    zip.Close();
                }
            }
            return bmp;
        }
    }
}
